package cn.com.dhcc.turbo.service.queue.tlq;

import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.com.dhcc.app.core.AppEnv.ParaGetTool;
import cn.com.dhcc.app.core.CM;
import cn.com.dhcc.app.core.exception.DaoException;
import cn.com.dhcc.app.core.exception.NiceException;
import cn.com.dhcc.app.core.exception.ServiceException;
import cn.com.dhcc.app.core.handler.dbhandler.SingleTransationCircleWithOutResult;
import cn.com.dhcc.app.core.handler.modulehandler.WhereCondition;
import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.service.Log.LOGTYPE;
import cn.com.dhcc.app.core.util.JsonUtil;
import cn.com.dhcc.app.pub.core.consts.TlqConfig;
import cn.com.dhcc.turbo.dao.registry.QueueDao;
import cn.com.dhcc.turbo.entity.registry.NodeInfo;
import cn.com.dhcc.turbo.entity.registry.NodePipeline;
import cn.com.dhcc.turbo.entity.registry.Queue;
import cn.com.dhcc.turbo.entity.registry.SynchronizeInfo.SyncOperType;
import cn.com.dhcc.turbo.entity.registry.SynchronizeInfo.SyncType;
import cn.com.dhcc.turbo.service.registry.NodeInfoService;
import cn.com.dhcc.turbo.service.registry.NodePipelineService;
import cn.com.dhcc.turbo.service.registry.sync.SynchronizeHandler;
import cn.com.dhcc.turbo.service.registry.vo.PipeLineTlq;


/**
 * tlq迁移
 * @author Administrator
 *
 */
@Service
public class TlqMoveService {
	private Logger loger=Log.getLogger(LOGTYPE.TURBO);

	@Autowired
	private NodePipelineService nodePipelineService;
	@Autowired
	SynchronizeHandler synchronizeHandler;
	@Autowired
	QueueDao queueDao;
	@Autowired
	TlqOptService tlqOptService;
	@Autowired
	NodeInfoService nodeInfoService;
	/**
	 * 本地更新服务
	 * @param nodePipeline
	 */
	public void updateLocal(String fromIp,String tlqIp) throws ServiceException{
		//1.判断是否需要更新
		NodeInfo node=nodeInfoService.getLocalNode();
		final NodePipeline local=nodePipelineService.getByNodeIdAndIp(node.getId(), fromIp);//获取本节点tlq信息
		PipeLineTlq tlq=JsonUtil.toObject(local.getParamStr(), PipeLineTlq.class);
		if (tlq.getBrokerIp().equals(tlqIp) && tlq.getJmsPort()==TlqConfig.TLQ_JMS_PORT  && TlqConfig.TLQ_SUPERVISE_PORT == tlq.getSupervisePort()) {
			return;
		}
		
		//2.更新nodePileline信息,更新queue信息
		loger.info("更新nodePileline信息");
		tlq.setBrokerIp(tlqIp);
		local.setParamStr(JsonUtil.toJson(tlq));
		local.setMtime(new Date());
		nodePipelineService.update(local);//更新nodepileline
		
		//3.更新缓存
		TlqCache.regionMap.clear();
		TlqCache.tLQOptObjFactoryMap.clear();
		TlqCache.jmsTemplateMap.clear();
		
		//4.写回配置文件 TODO BY 
		String key = "tlq.broker.ip";
		System.out.println("改写前："+ParaGetTool.getPara(key));
		//改写
		ParaGetTool.setAppPara(key,tlqIp);
		//写入
		ParaGetTool.saveAppPara();
		
		//6.同步
		try {
			synchronizeHandler.syncToAllNodesFromLocalNode(SyncType.PILE_LINE, false, local, SyncOperType.UPDATE,true);
		} catch (NiceException e) {
			throw new ServiceException(e.getMessage());
		}
	
	}
	
	//更新远程
	public void updateRemote(final NodePipeline nodePipeline) throws ServiceException{
		//1.检查是否有该节点的其他节点，如果已经有同节点的其他通道信息，则忽略该通道
		WhereCondition condition=new WhereCondition();
		condition.where().eq("node_id", nodePipeline.getNodeId());
		List<NodePipeline> list=nodePipelineService.list(condition);
		if (list!=null && !list.isEmpty() ) {
			for (NodePipeline n : list) {
				if (!n.getId().equals(nodePipeline.getId())) {//表明存在一个传输通道与要更新的传输通道不是一个(可能是集群的)，但是节点ID相同
					loger.error("传输通道已经存在["+n+"],请求更新["+nodePipeline+"]", new Exception("传输通道更新异常忽略"));
					return;//忽略这个节点不在更新,这个通道是集群中的某个通道信息，并且不是该节点所需要的通道信息，因此忽略更新
				}
			}
		}else{//如果为空，说明没有该通道信息，此时不需要更新
			return;
		}
		
		//2.判断是否需要更新
		final NodePipeline local=nodePipelineService.get(nodePipeline.getId());//获取本节点tlq信息
		final PipeLineTlq remoteTlq=JsonUtil.toObject(nodePipeline.getParamStr(), PipeLineTlq.class);
		try {
			CM.getDao().doInSingleTransationCircle("更新通道信息", new SingleTransationCircleWithOutResult() {
				public void actionInCircle() throws RuntimeException {
					try {
						nodePipeline.setMtime(new Date());
						nodePipelineService.insertOrUpdate(nodePipeline);//更新通道信息
						if (local!=null) {
							PipeLineTlq srcTlq=JsonUtil.toObject(local.getParamStr(), PipeLineTlq.class);
							if (!srcTlq.getBrokerIp().equals(remoteTlq.getBrokerIp())) {//ip如果变化了就更新队列信息
								queueDao.updateDestIp(srcTlq.getBrokerIp(), remoteTlq.getBrokerIp());//更新队列信息
							}
						}
					} catch (Exception e) {
						throw new RuntimeException();
					}
				}
			});
		} catch (DaoException e) {
			loger.error("更新失败",e);
			throw new ServiceException("更新来自通道信息{"+nodePipeline+"}失败");
		}
		if (local!=null) {
			final PipeLineTlq localTlq=JsonUtil.toObject(local.getParamStr(), PipeLineTlq.class);
			if (localTlq.getBrokerIp().equals(remoteTlq) && localTlq.getJmsPort()==remoteTlq.getJmsPort()  && remoteTlq.getSupervisePort() == localTlq.getSupervisePort()) {
				return;
			}
		}
		
		if (local!=null) {
			PipeLineTlq srcTlq=JsonUtil.toObject(local.getParamStr(), PipeLineTlq.class);
			if (srcTlq.getBrokerIp().equals(remoteTlq.getBrokerIp())) {//ip如果没有变化，就不需要初始化发送队列了
				return;
			}
		}
		
		//初始化队列
		WhereCondition cnd = new WhereCondition();
		cnd.where().eq("queue_type", Queue.QueueType.SQ.value())
		.and().eq("DEST_IP", remoteTlq.getBrokerIp());
		cnd.orderBy("queue_name");
		try {
			List<Queue> queues=queueDao.list(cnd);
			if (queues!=null && !queues.isEmpty()) {
				for (Queue queue : queues) {
					tlqOptService.initOrUpdateSendQueue(queue);
				}
			}
		} catch (DaoException e) {
			throw new ServiceException("初始化队列失败");
		}
		
	}
}
